package requestModel

import (
	"encoding/xml"
	"fmt"
	"solargis/config"
	"time"
)

const (
	NSDefault = "http://geomodel.eu/schema/data/request"
	NSWs      = "http://geomodel.eu/schema/ws/data"
	NSGeo     = "http://geomodel.eu/schema/common/geo"
	NSPv      = "http://geomodel.eu/schema/common/pv"
	NSXsi     = "http://www.w3.org/2001/XMLSchema-instance"
)

type DataDeliveryRequest struct {
	XMLName    xml.Name   `xml:"ws:dataDeliveryRequest"`
	DateFrom   string     `xml:"dateFrom,attr"`
	DateTo     string     `xml:"dateTo,attr"`
	Site       Site       `xml:"site"`
	Processing Processing `xml:"processing"`
	Xmlns      string     `xml:"xmlns,attr"`
	XmlnsWs    string     `xml:"xmlns:ws,attr"`
	XmlnsGeo   string     `xml:"xmlns:geo,attr"`
	XmlnsPv    string     `xml:"xmlns:pv,attr"`
	XmlnsXsi   string     `xml:"xmlns:xsi,attr"`
}

type Processing struct {
	Keys           string `xml:"key,attr"`
	Summarization  string `xml:"summarization,attr"`
	TerrainShading bool   `xml:"terrainShading,attr"`
	TimeZone       string `xml:"timeZone"`
	TimestampType  string `xml:"timestampType"`
}

type Site struct {
	ID         string     `xml:"id,attr"`
	Lat        string     `xml:"lat,attr"`
	Lng        string     `xml:"lng,attr"`
	Name       string     `xml:"name,attr"`
	Terrain    Terrain    `xml:"geo:terrain"`
	Horizon    string     `xml:"geo:horizon"`
	PVGeometry PVGeometry `xml:"pv:geometry"`
	PVSystem   PVSystem   `xml:"pv:system"`
}

type PVGeometry struct {
	Type              string   `xml:"xsi:type,attr"`
	Azimuth           *float64 `xml:"azimuth,attr,omitempty"`
	Tilt              *float64 `xml:"tilt,attr,omitempty"`
	AxisTilt          *float64 `xml:"axisTilt,attr,omitempty"`
	RotationLimitEast *float64 `xml:"rotationLimitEast,attr,omitempty"`
	RotationLimitWest *float64 `xml:"rotationLimitWest,attr,omitempty"`
	TiltLimitMin      *float64 `xml:"tiltLimitMin,attr,omitempty"`
	TiltLimitMax      *float64 `xml:"tiltLimitMax,attr,omitempty"`
	BackTracking      *bool    `xml:"backTracking,attr,omitempty"`
}

type PVSystem struct {
	InstalledPower   float64  `xml:"installedPower,attr"`
	InstallationType string   `xml:"installationType,attr"`
	DateStartup      string   `xml:"dateStartup,attr"`
	SelfShading      bool     `xml:"selfShading,attr"`
	Module           Module   `xml:"pv:module"`
	Inverter         Inverter `xml:"pv:inverter"`
	Losses           Losses   `xml:"pv:losses"`
	Topology         Topology `xml:"pv:topology"`
}
type Module struct {
	Type                     string  `xml:"type,attr"`
	DegradationFirstYear     float64 `xml:"pv:degradationFirstYear"`
	Degradation              float64 `xml:"pv:degradation"`
	SurfaceReflectance       float64 `xml:"pv:surfaceReflectance"`
	NominalOperatingCellTemp float64 `xml:"pv:nominalOperatingCellTemp"`
	PmaxCoeff                float64 `xml:"pv:PmaxCoeff"`
}

// 恒定效率：<efficiency xsi:type="pv:EfficiencyConstant" value="97.5"/>
// 效率曲线：<efficiency xsi:type="pv:EfficiencyCurve" dataPairs="0:85.6 0.5:96.2 1:98 1.5:97 2:97 2.5:96 3.0:96"/>
type Inverter struct {
	LimitationACPower float64    `xml:"pv:limitationACPower"`
	Efficiency        Efficiency `xml:"pv:efficiency"`
}
type Efficiency struct {
	Type      string   `xml:"xsi:type,attr"`
	Percent   *float64 `xml:"percent,attr,omitempty"`
	DataPairs *string  `xml:"dataPairs,attr,omitempty"`
}
type Losses struct {
	AC AC `xml:"pv:acLosses"`
	DC DC `xml:"pv:dcLosses"`
}
type AC struct {
	Cables      float64 `xml:"cables,attr"`
	Transformer float64 `xml:"transformer,attr"`
}
type DC struct {
	Cables               float64  `xml:"cables,attr"`
	Mismatch             float64  `xml:"mismatch,attr"`
	SnowPollution        *float64 `xml:"snowPollution,attr,omitempty"`
	MonthlySnowPollution *string  `xml:"monthlySnowPollution,attr,omitempty"`
}
type Topology struct {
	XsiType         string  `xml:"xsi:type,attr"`
	RelativeSpacing float64 `xml:"relativeSpacing,attr"`
	Type            string  `xml:"type,attr"`
}

type Terrain struct {
	Elevation float64 `xml:"elevation,attr"`
	Azimuth   float64 `xml:"azimuth,attr"`
	Tilt      float64 `xml:"tilt,attr"`
}

func BuildDailyRequest(cfg *config.Config, i int) ([]byte, error) {
	if cfg == nil {
		return nil, fmt.Errorf("config is nil")
	}

	dailyCfg := cfg.Request
	req := DataDeliveryRequest{

		Site: Site{
			ID:   dailyCfg.Site.ID,
			Name: dailyCfg.Site.Name,
			Lat:  fmt.Sprintf("%.6f", dailyCfg.Site.Lat),
			Lng:  fmt.Sprintf("%.6f", dailyCfg.Site.Lng),
			Terrain: Terrain{
				Elevation: dailyCfg.Site.Terrain.Elevation,
				Azimuth:   dailyCfg.Site.Terrain.Azimuth,
				Tilt:      dailyCfg.Site.Terrain.Tilt,
			},
			Horizon:    dailyCfg.Site.Horizon,
			PVGeometry: buildPVGeometry(cfg),
			PVSystem:   buildPVSystem(cfg),
		},
		Processing: Processing{
			Keys:           dailyCfg.Processing.Keys,
			Summarization:  dailyCfg.Processing.Summarization,
			TerrainShading: dailyCfg.Processing.TerrainShading,
			TimeZone:       dailyCfg.Processing.TimeZone,
			TimestampType:  dailyCfg.Processing.TimestampType,
		},
		Xmlns:    NSDefault,
		XmlnsWs:  NSWs,
		XmlnsPv:  NSPv,
		XmlnsGeo: NSGeo,
		XmlnsXsi: NSXsi,
	}

	// 处理 SnowPollution 和 MonthlySnowPollution 冲突
	if dailyCfg.Site.PVSystem.Losses.DC.SnowPollution != 0 {
		req.Site.PVSystem.Losses.DC.SnowPollution = &dailyCfg.Site.PVSystem.Losses.DC.SnowPollution
	} else {
		monthlySnowPollution := dailyCfg.Site.PVSystem.Losses.DC.MonthlySnowPollution
		req.Site.PVSystem.Losses.DC.MonthlySnowPollution = &monthlySnowPollution
	}
	if i == 0 {
		req.DateTo = time.Now().Format("2006-01-02")
		req.DateFrom = time.Now().Format("2006-01-02")
	} else if i >= 1 && i <= 14 {
		req.DateFrom = time.Now().AddDate(0, 0, 1).Format("2006-01-02")
		req.DateTo = time.Now().AddDate(0, 0, i).Format("2006-01-02")
	}

	return xml.MarshalIndent(req, "", "  ")
}

func buildPVSystem(cfg *config.Config) PVSystem {
	dailyCfg := cfg.Request
	return PVSystem{
		InstalledPower:   dailyCfg.Site.PVSystem.InstalledPower,
		InstallationType: dailyCfg.Site.PVSystem.InstallationType,
		DateStartup:      dailyCfg.Site.PVSystem.DateStartup,
		SelfShading:      dailyCfg.Site.PVSystem.SelfShading,
		Module: Module{
			Type:                     dailyCfg.Site.PVSystem.Module.Type,
			DegradationFirstYear:     dailyCfg.Site.PVSystem.Module.DegradationFirstYear,
			Degradation:              dailyCfg.Site.PVSystem.Module.Degradation,
			SurfaceReflectance:       dailyCfg.Site.PVSystem.Module.SurfaceReflectance,
			NominalOperatingCellTemp: dailyCfg.Site.PVSystem.Module.NominalOperatingCellTemp,
			PmaxCoeff:                dailyCfg.Site.PVSystem.Module.PmaxCoeff,
		},
		Inverter: Inverter{
			LimitationACPower: dailyCfg.Site.PVSystem.Inverter.LimitationACPower,
			Efficiency:        buildEfficiency(cfg),
		},
		Losses: Losses{
			AC: AC{
				Cables:      dailyCfg.Site.PVSystem.Losses.AC.Cables,
				Transformer: dailyCfg.Site.PVSystem.Losses.AC.Transformer,
			},
			DC: DC{
				Cables:   dailyCfg.Site.PVSystem.Losses.DC.Cables,
				Mismatch: dailyCfg.Site.PVSystem.Losses.DC.Mismatch,
			},
		},
		Topology: Topology{
			XsiType:         dailyCfg.Site.PVSystem.Topology.XsiType,
			RelativeSpacing: dailyCfg.Site.PVSystem.Topology.RelativeSpacing,
			Type:            dailyCfg.Site.PVSystem.Topology.Type,
		},
	}
}

// 构建 PVGeometry 的辅助函数
/*
*固定角度几何形状：<pv:geometry xsi:type="pv:GeometryFixedOneAngle" azimuth="180" tilt="25"/>
水平单轴跟踪器：<pv:geometry xsi:type="pv:GeometryOneAxisHorizontalNS" rotationLimitEast="-90" rotationLimitWest="90" backTracking="true" azimuth="180"/>
倾斜单轴跟踪器：<pv:geometry xsi:type="pv:GeometryOneAxisInclinedNS" axisTilt="30" rotationLimitEast="-90" rotationLimitWest="90" backTracking="true"  azimuth="180"/>
垂直单轴跟踪器：<pv:geometry xsi:type="pv:GeometryOneAxisVertical" tilt="25" rotationLimitEast="-180" rotationLimitWest="180" backTracking="true"/>
双轴天文跟踪器： <pv:geometry xsi:type="pv:GeometryTwoAxisAstronomical" rotationLimitEast="-180" rotationLimitWest="180"  tiltLimitMin="10" tiltLimitMax="60" backTracking="true"/>
*/
func buildPVGeometry(cfg *config.Config) PVGeometry {
	if cfg == nil {
		return PVGeometry{}
	}
	var cfgGeometry = cfg.Request.Site.PVGeometry
	pvGeometry := PVGeometry{
		Type: cfgGeometry.Type,
	}

	switch cfgGeometry.Type {
	case "pv:GeometryFixedOneAngle":
		pvGeometry.Azimuth = &cfgGeometry.Azimuth
		pvGeometry.Tilt = &cfgGeometry.Tilt
	case "pv:GeometryOneAxisHorizontalNS":
		pvGeometry.RotationLimitEast = &cfgGeometry.RotationLimitEast
		pvGeometry.RotationLimitWest = &cfgGeometry.RotationLimitWest
		pvGeometry.BackTracking = &cfgGeometry.BackTracking
		pvGeometry.Azimuth = &cfgGeometry.Azimuth
	case "pv:GeometryOneAxisInclinedNS":
		pvGeometry.AxisTilt = &cfgGeometry.AxisTilt
		pvGeometry.RotationLimitEast = &cfgGeometry.RotationLimitEast
		pvGeometry.RotationLimitWest = &cfgGeometry.RotationLimitWest
		pvGeometry.BackTracking = &cfgGeometry.BackTracking
		pvGeometry.Azimuth = &cfgGeometry.Azimuth
	case "pv:GeometryOneAxisVertical":
		pvGeometry.Tilt = &cfgGeometry.Tilt
		pvGeometry.RotationLimitEast = &cfgGeometry.RotationLimitEast
		pvGeometry.RotationLimitWest = &cfgGeometry.RotationLimitWest
		pvGeometry.BackTracking = &cfgGeometry.BackTracking
	case "pv:GeometryTwoAxisAstronomical":
		pvGeometry.RotationLimitEast = &cfgGeometry.RotationLimitEast
		pvGeometry.RotationLimitWest = &cfgGeometry.RotationLimitWest
		pvGeometry.TiltLimitMin = &cfgGeometry.TiltLimitMin
		pvGeometry.TiltLimitMax = &cfgGeometry.TiltLimitMax
		pvGeometry.BackTracking = &cfgGeometry.BackTracking
	default:
		pvGeometry.Azimuth = &cfgGeometry.Azimuth
		pvGeometry.Tilt = &cfgGeometry.Tilt
	}

	return pvGeometry
}

// 构建 Efficiency 的辅助函数
func buildEfficiency(cfg *config.Config) Efficiency {
	if cfg == nil {
		return Efficiency{}
	}
	var cfgEfficiencyConfig = cfg.Request.Site.PVSystem.Inverter.Efficiency
	efficiency := Efficiency{
		Type: cfgEfficiencyConfig.Type,
	}

	switch cfgEfficiencyConfig.Type {
	case "pv:EfficiencyConstant":
		efficiency.Percent = &cfgEfficiencyConfig.Percent
	case "pv:EfficiencyCurve":
		efficiency.DataPairs = &cfgEfficiencyConfig.DataPairs
	default:
		efficiency.Percent = &cfgEfficiencyConfig.Percent
	}

	return efficiency
}
